package com.example.simplerpc.client;

import com.example.simplerpc.client.discover.ServiceDiscover;
import com.example.simplerpc.client.net.NetClient;
import com.example.simplerpc.common.protocol.MessageProtocol;
import com.example.simplerpc.common.protocol.RpcRequest;
import com.example.simplerpc.common.protocol.RpcResponse;
import com.example.simplerpc.common.service.Service;
import com.example.simplerpc.exception.RpcException;
import lombok.Data;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * @Classname: ClientProxyFactory
 * @Description:
 * @Author: Stonffe
 * @Date: 2022/12/19 10:50
 */
@Data
public class ClientProxyFactory {
    private ServiceDiscover serviceDiscover;
    private Map<String, MessageProtocol> messageProtocol;
    private NetClient netClient;
    private Map<Class<?>,Object> objectCache = new HashMap<>();

    private class ClientInvocationHandler implements InvocationHandler{
        private Class<?> clazz;
        private Random random = new Random();
        public ClientInvocationHandler(Class<?> clazz){
            this.clazz = clazz;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String serviceName = clazz.getName();
            List<Service> services = serviceDiscover.getServices(serviceName);
            if (services == null || services.isEmpty()) {
                throw new RpcException("No provider available!");
            }
            Service service = services.get(random.nextInt(services.size()));
            RpcRequest request = new RpcRequest();
            request.setServiceName(service.getName());
            request.setMethod(method.getName());
            request.setParamTypes(method.getParameterTypes());
            request.setParameters(args);
            MessageProtocol protocol = ClientProxyFactory.this.messageProtocol.get(service.getProtocol());
            byte[] data = protocol.marshallingReqest(request);
            byte[] respData = netClient.sendRequest(data, service);
            RpcResponse response = protocol.unmarshallingResponse(respData);
            if (response.getException() != null) {
                throw response.getException();
            }
            return response.getReturnValue();
        }
    }
}
